/*
  ODPort.cpp - 
*/

#include "ODPort.h"
#include "WProgram.h"
#include "ODADebug.h"

const uint8_t UNCHANGED = 2;

Port::Port() {
  //Preimposta l'oggetto come "non inizializzato"
  _pin = 254;
  _type = 254;    //254=UNDEFINED, INPUT, OUTPUT
}

void Port::initInput(uint8_t pin) {
  //Inizializza la porta come INPUT
  initPort(pin, INPUT);
  
  //Legge il valore iniziale e inizializza le variabili di controllo
  readPort();
  _lastChangeTime = 0;
  _lastSentStatus = _status;
  
  //Imposta il valore di default per il filtro debounce
  setDebounce(40);
  
  //Di default attiva la resistenza di pull-up
  enablePullup();
}

void Port::initOutput(uint8_t pin, uint8_t initStatus) {  
  //Inizializza la porta come OUTPUT
  initPort(pin, OUTPUT);

  //Imposta lo stato iniziale della porta
  setStatus(initStatus);
  _lastSentStatus = _status;
  
  //Disattiva il debounce in quanto non ha senso per porte di Output
  _debounceTime = 0;
}

void Port::initPort(uint8_t pin, uint8_t type) {
  //Salva il numero del pin e il tipo di porta tra gli attributi privati dell'oggetto
  _pin = pin;
  _type = type;

  //Imposta la porta fisica sul microcontrollore
  pinMode(_pin, _type);
  
}

void Port::readPort() {
  uint8_t value = digitalRead(_pin);
  
  if (value != _status) {
    _lastChangeTime = millis();
    _status = value;
  }
}

uint8_t Port::getStatus() {
  if (_type == 254) return UNCHANGED;
  
  if (_type == OUTPUT) return _status;

  if (_type == INPUT) readPort();
  
  if (_lastSentStatus != _status && millis() >= _lastChangeTime + _debounceTime) {
    _lastSentStatus = _status;
#ifdef __DEBUG
    debugPort("Port::getStatus", _pin, _status);
#endif
    return _status;
  }
  
  return UNCHANGED; 
}

void Port::setStatus(uint8_t newStatus) {
  if (_type == 254) return;

  _status = newStatus;
  _lastSentStatus = newStatus;
  _lastChangeTime = millis();
  
  if (_type == OUTPUT) digitalWrite(_pin, _status);
  
#ifdef __DEBUG
  debugPort("Port::setStatus", _pin, _status);
#endif
}

void Port::enablePullup() {
  if (_type == OUTPUT || _type == 254) return;
  digitalWrite(_pin, HIGH);
}

void Port::disablePullup() {
  if (_type == OUTPUT || _type == 254) return;
  digitalWrite(_pin, LOW);
}

void Port::setDebounce(int debounceTime) {
  if (_type == OUTPUT || _type == 254) return;
    
  _debounceTime = debounceTime;
}
